package com.swotxu.mall.product.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.swotxu.common.constant.ProductConstant;
import com.swotxu.common.to.SkuHasStockTo;
import com.swotxu.common.to.SkuReductionTo;
import com.swotxu.common.to.SpuBoundTo;
import com.swotxu.common.to.es.SkuESModel;
import com.swotxu.common.utils.ComparableUtil;
import com.swotxu.common.utils.PageUtils;
import com.swotxu.common.utils.Query;
import com.swotxu.common.utils.R;
import com.swotxu.mall.product.dao.SpuInfoDao;
import com.swotxu.mall.product.entity.AttrEntity;
import com.swotxu.mall.product.entity.BrandEntity;
import com.swotxu.mall.product.entity.CategoryEntity;
import com.swotxu.mall.product.entity.ProductAttrValueEntity;
import com.swotxu.mall.product.entity.SkuImagesEntity;
import com.swotxu.mall.product.entity.SkuInfoEntity;
import com.swotxu.mall.product.entity.SkuSaleAttrValueEntity;
import com.swotxu.mall.product.entity.SpuInfoDescEntity;
import com.swotxu.mall.product.entity.SpuInfoEntity;
import com.swotxu.mall.product.feign.CouponFeginService;
import com.swotxu.mall.product.feign.SearchFeginService;
import com.swotxu.mall.product.feign.WareFeginService;
import com.swotxu.mall.product.service.*;
import com.swotxu.mall.product.vo.Attr;
import com.swotxu.mall.product.vo.BaseAttrs;
import com.swotxu.mall.product.vo.Skus;
import com.swotxu.mall.product.vo.SpuSaveVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;


@Slf4j
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    SpuInfoDescService spuInfoDescService;
    @Autowired
    SpuImagesService spuImagesService;
    @Autowired
    AttrService attrService;
    @Autowired
    ProductAttrValueService productAttrValueService;
    @Autowired
    SkuInfoService skuInfoService;
    @Autowired
    SkuImagesService skuImagesService;
    @Autowired
    SkuSaleAttrValueService skuSaleAttrValueService;
    @Autowired
    CouponFeginService couponFeginService;
    @Autowired
    BrandService brandService;
    @Autowired
    CategoryService categoryService;
    @Autowired
    WareFeginService wareFeginService;
    @Autowired
    SearchFeginService searchFeginService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * TODO 后期处理分布式事务
     * @param spuSaveVo
     */
    @Override
    @Transactional
    public void saveSpuInfo(SpuSaveVo spuSaveVo) {
        // 1、保存spu的基本信息 pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(spuSaveVo, spuInfoEntity);
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        this.baseMapper.insert(spuInfoEntity);

        Long spuId = spuInfoEntity.getId();

        // 2、保存spu的描述信息 pms_spu_info_desc
        List<String> decriptList = spuSaveVo.getDecript();
        SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
        descEntity.setSpuId(spuId);
        descEntity.setDecript(String.join(",", decriptList));
        spuInfoDescService.save(descEntity);

        // 3、保存spu的图片集 pms_spu_images
        spuImagesService.saveImages(spuId, spuSaveVo.getImages());

        // 4、保存spu的规格参数 pms_product_attr_value
        List<BaseAttrs> baseAttrs = spuSaveVo.getBaseAttrs();
        List<ProductAttrValueEntity> attrValueEntities = baseAttrs.stream().map(baseAttr -> {
            ProductAttrValueEntity attrValueEntity = new ProductAttrValueEntity();
            attrValueEntity.setAttrId(baseAttr.getAttrId());
            AttrEntity attrEntity = attrService.getById(baseAttr.getAttrId());
            attrValueEntity.setAttrName(attrEntity.getAttrName());
            attrValueEntity.setAttrValue(baseAttr.getAttrValues());
            attrValueEntity.setQuickShow(baseAttr.getShowDesc());
            attrValueEntity.setSpuId(spuId);
            return attrValueEntity;
        }).collect(Collectors.toList());
        productAttrValueService.saveBatch(attrValueEntities);

        // 5、保存spu的积分信息 mall_sms（库） -> sms_spu_bounds
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        BeanUtils.copyProperties(spuSaveVo.getBounds(), spuBoundTo);
        spuBoundTo.setSpuId(spuId);
        R resultWithSpuBounds = couponFeginService.saveSpuBounds(spuBoundTo);
        if (resultWithSpuBounds.getCode() != 0) {
            log.warn("远程保存spu积分信息失败！");
        }

        // 6、保存当前spu对应的所有sku信息
        List<Skus> skusList = spuSaveVo.getSkus();
        for (Skus skus : skusList) {
            // 6.1)、保存sku的基本信息 pms_sku_info
            String defaultImgUrl = skus.getImages().stream()
                    .filter(images -> images.getDefaultImg() == 1)
                    .findFirst().map(images -> images.getImgUrl()).orElse("");

            SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
            BeanUtils.copyProperties(skus, skuInfoEntity);
            skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
            skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
            skuInfoEntity.setSaleCount(0L);
            skuInfoEntity.setSpuId(spuId);
            skuInfoEntity.setSkuDefaultImg(defaultImgUrl);
            skuInfoService.save(skuInfoEntity);

            Long skuId = skuInfoEntity.getSkuId();

            // 6.2)、保存sku的图片集 pms_sku_images
            List<SkuImagesEntity> skuImagesEntityList = skus.getImages().stream()
                    // 没有图片路径信息的，不保存数据库
                    .filter(img -> StringUtils.isNotEmpty(img.getImgUrl()))
                    .map(img -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                }).collect(Collectors.toList());

            skuImagesService.saveBatch(skuImagesEntityList);

            // 6.3)、保存sku的销售属性信息 pms_sku_sale_attr_value
            List<Attr> attrList = skus.getAttr();
            List<SkuSaleAttrValueEntity> saleAttrValueEntities = attrList.stream().map(attr -> {
                SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                BeanUtils.copyProperties(attr, skuSaleAttrValueEntity);
                skuSaleAttrValueEntity.setSkuId(skuId);

                return skuSaleAttrValueEntity;
            }).collect(Collectors.toList());
            skuSaleAttrValueService.saveBatch(saleAttrValueEntities);

            // 6.4)、保存sku的优惠满减等信息 夸库 -> mall_sms
            // sms_sku_ladder 打折、sms_sku_full_reduction 满减、sms_member_price 会员价
            SkuReductionTo skuReductionTo = new SkuReductionTo();
            BeanUtils.copyProperties(skus, skuReductionTo);
            skuReductionTo.setSkuId(skuId);
            if (skuReductionTo.getFullCount() > 0 || ComparableUtil.gtZeroOfBigDecimal(skuReductionTo.getFullPrice())) {
                R resultWithSkuReduction = couponFeginService.saveSkuReduction(skuReductionTo);
                if (resultWithSkuReduction.getCode() != 0) {
                    log.warn("远程保存sku优惠信息失败！spuId: {}, skuId: {}", spuId, skuId);
                }
            }
        }
    }

    /**
     *    page: 1,//当前页码
     *    limit: 10,//每页记录数
     *    sidx: 'id',//排序字段
     *    order: 'asc/desc',//排序方式
     *    key: '华为',//检索关键字
     *    catelogId: 6,//三级分类id
     *    brandId: 1,//品牌id
     *    status: 0,//商品状态
     *
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        LambdaQueryWrapper<SpuInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        String key = (String) params.get("key");
        lambdaQueryWrapper.and(StringUtils.isNotEmpty(key), wrapper -> {
            wrapper.eq(SpuInfoEntity::getId, key).or().like(SpuInfoEntity::getSpuName, key);
        });

        String status = (String) params.get("status");
        lambdaQueryWrapper.eq(ComparableUtil.gtZeroOfInteger(status), SpuInfoEntity::getPublishStatus, status);

        String brandId = (String) params.get("brandId");
        lambdaQueryWrapper.eq(ComparableUtil.gtZeroOfLong(brandId), SpuInfoEntity::getBrandId, brandId);

        String catelogId = (String) params.get("catelogId");
        lambdaQueryWrapper.eq(ComparableUtil.gtZeroOfLong(catelogId), SpuInfoEntity::getCatalogId, catelogId);

        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                lambdaQueryWrapper
        );
        return new PageUtils(page);
    }

    @Override
    public void spuUp(Long spuId) {
        // 1、查出当前 spuid对应的sku信息，品牌名
        List<SkuInfoEntity> skuInfoEntities = skuInfoService.list(new LambdaQueryWrapper<SkuInfoEntity>().eq(SkuInfoEntity::getSpuId, spuId));
        if (CollectionUtils.isEmpty(skuInfoEntities)) {
            log.info("查无商品信息！spuId: {}", spuId);
            return;
        }
        // a）查询品牌信息
        BrandEntity brandEntity = brandService.getById(skuInfoEntities.get(0).getBrandId());
        // b）查询分类信息
        CategoryEntity catalogEntity = categoryService.getById(skuInfoEntities.get(0).getCatalogId());
        // c）查询当前sku所有可以被用来检索的规格属性
        List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseAttrListforspu(spuId);
        // 查出所有可被检索的规格属性ID
        List<Long> attrIds = baseAttrs.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());
        List<Long> searchAttrIds = attrService.selectSearchAttrIds(attrIds);
        //根据可被检索的规格属性ID，筛选并封装成 AttrESModel
        List<SkuESModel.AttrESModel> attrESModels = baseAttrs.stream()
                .filter(baseAttr -> searchAttrIds.contains(baseAttr.getAttrId()))
                .map(searchBaseAttr -> {
                    SkuESModel.AttrESModel attrESModel = new SkuESModel.AttrESModel();
                    BeanUtils.copyProperties(searchBaseAttr, attrESModel);
                    return attrESModel;
                }).collect(Collectors.toList());

        // d）远程调用库存系统，检查是否有库存 - hasStock
        List<Long> skuIds = skuInfoEntities.stream().map(SkuInfoEntity::getSkuId).distinct().collect(Collectors.toList());
        Optional<Map<Long, Boolean>> stockMapOptional = getSkuHasStock(skuIds);

        // 2、封装每个sku信息
        List<SkuESModel> upProductList = skuInfoEntities.stream().map(skuInfoEntity -> {
            // 组装需要上架的数据
            SkuESModel skuESModel = new SkuESModel();
            BeanUtils.copyProperties(skuInfoEntity, skuESModel);
            // 处理不一致的字段 skuPrice,skuImg
            skuESModel.setSkuPrice(skuInfoEntity.getPrice());
            skuESModel.setSkuImg(skuInfoEntity.getSkuDefaultImg());
            // 处理缺失的数据 hasStock,hotScore,brandName,brandImg,catalogName,attrs
            skuESModel.setBrandName(brandEntity.getName());
            skuESModel.setBrandImg(brandEntity.getLogo());
            skuESModel.setCatalogName(catalogEntity.getName());
            skuESModel.setAttrs(attrESModels);
            // 远程调用库存系统，检查是否有库存 - hasStock
            skuESModel.setHasStock(stockMapOptional.map(map -> map.get(skuESModel.getSkuId())).orElse(true));
            // TODO e、热度评分。默认 0 - hotScore
            skuESModel.setHotScore(0L);

            return skuESModel;
        }).collect(Collectors.toList());

        // 3、将数据发送给 ES服务保存：mall-search
        R upResult = searchFeginService.productStatusUp(upProductList);
        if (upResult.isOk()) {
            // 上架成功，修改商品状态
            SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
            spuInfoEntity.setId(spuId);
            spuInfoEntity.setPublishStatus(ProductConstant.SpuPublishStatusEnum.SPU_UP.getCode());
            this.baseMapper.updateById(spuInfoEntity);
        } else {
            // TODO 上架失败，重试机制，接口幂等性问题
            log.warn("商品上架远程调用Search服务失败");
        }
    }

    private Optional<Map<Long, Boolean>> getSkuHasStock(List<Long> skuIds) {
        Optional<Map<Long, Boolean>> stockMapOptional = Optional.empty();
        try {
            R skuHasStockResult = wareFeginService.getSkuHasStock(skuIds);
            stockMapOptional = Optional.ofNullable(skuHasStockResult.getData(new TypeReference<List<SkuHasStockTo>>() {}))
                    .map(toList -> toList.stream().collect(
                            Collectors.toMap(SkuHasStockTo::getSkuId, SkuHasStockTo::getHasStock)
                            )
                    );
        } catch (Exception e) {
            log.warn("库存服务查询异常！", e);
        }
        return stockMapOptional;
    }

    @Override
    public SpuInfoEntity getSpuInfoBySkuId(Long skuId) {
        SkuInfoEntity byId = skuInfoService.getById(skuId);
        return getById(byId.getSpuId());
    }
}